package au.org.ala.collectors

import au.com.bytecode.opencsv.CSVReader
import java.text.NumberFormat
import groovy.sql.Sql

class DataLoadService {

    static transactional = false
    javax.sql.DataSource dataSource

    /*****
     *****  Update from CSV file
     *****/
    def columns = ["name","period","work","biog","imageUri"]

    def loadFromCSV(String filename) {

        // clear
        def sql = new Sql(dataSource)
        sql.execute("delete from person")

        CSVReader reader = new CSVReader(new FileReader(filename))
        String [] nextLine;
        int headerLines = 0
        int dataLines = 0
        int exists = 0
        int updates = 0
        int failures = 0
        int inserts = 0

        log.info "================================= importing collectors ======="
		while ((nextLine = reader.readNext()) != null) {

            /* create a params map from the csv data */
            def params = [:]
            columns.eachWithIndex {it, i ->
                //println "i=${i} value=${nextLine[i]}"
                if (nextLine[i]) {
                    // eliminate any \ used for line breaks
                    params[it] = nextLine[i] //.replaceAll("" + (92 as char)," ")
                }
            }

            if (params.name != 'name' && params.name) {  // don't include the header row or blank rows
                dataLines++

                def person = new Person()
                /* --name-- */
                def fullName = params.name.trim()
                def familyName = fullName
                def foreNames = ""

                // trailing asterisk means the person supplied bio information
                person.personContributed = fullName[-1] == '*'

                // remove any trailing asterisk
                if (fullName[-1] == '*') {
                    fullName = fullName[0..-2]
                }

                // split on first comma
                def idx = fullName.indexOf(',')
                if (idx > 0) {
                    familyName = fullName[0..idx-1]
                    if (idx + 1 < fullName.size()) {
                        foreNames = fullName[idx+1..-1]
                    }
                } else {
                    // try splitting on a period (several names have periods after the surname)
                    def periodIdx = fullName.indexOf('.')
                    if (periodIdx > 0) {
                        familyName = fullName[0..periodIdx-1]
                        if (periodIdx + 1 < fullName.size()) {
                            foreNames = fullName[periodIdx+1..-1]
                        }
                    }
                }

                // extract alternate names
                // TODO:

                person.familyName = familyName
                person.foreNames = foreNames

                /* --period-- */
                def period = params.period?.trim()

                if (period) {
                    def dash = period.indexOf('-')
                    // handle fl.
                    if (period =~ "fl." || dash == -1) {
                        person.periodOfActivity = period
                    } else {
                        def from = ""
                        def to = ""
                        if (dash == 0) {  // -yyyy
                            to = period[1..-1]
                        } else if (dash == period.size()-1) {
                            from = period[0..-2]
                        } else {
                            from = period[0..dash-1]
                            to = period[dash+1..-1]
                        }
                        setYears(person, from, to)
                    }

                }

                /* --work-- */
                // TODO: need to differentiate between occupation and interest
                person.areaOfInterest = params.work?.trim()

                /* --biog-- */
                person.biog = params.biog

                /* --image-- */
                person.imageUri = params.imageUri

                if (!person.hasErrors() && person.save(flush: true)) {
                    inserts++
                    log.debug "Created person ${person.familyName}"
                } else {
                    failures++
                    log.warn "Failed to create person ${params.name}"
                    println "Failed to create person ${params.name}"
                    person.errors.each { log.info it }
                }
                //println "${person.yearOfBirth} to ${person.yearOfDeath} ${person.living?'    ':'obit'}\t\t${person.familyName}\t\t${person.foreNames}\t\t"
            }
            
        }
        def returnObj = new Expando()
        returnObj.headerLines = headerLines
        returnObj.dataLines = dataLines
        returnObj.inserts = inserts
        returnObj.failures = failures
        returnObj.exists = exists
        returnObj.updates = updates
        return returnObj
    }

    private void setYears(Person person, String from, String to) {
        person.yearOfBirth = getYear(from)
        person.yearOfBirthUncertain = (from =~ 'c.')
        person.yearOfDeath = getYear(to)
        person.yearOfDeathUncertain = (to =~ 'c.')
        person.living = (!to || to =~ 'ob.')
    }

    private int getYear(String yearStr) {
        if (!yearStr) return 0
        if (yearStr == '?') return -1  // uncertain

        // strip non-digits
        def digits = ""
        yearStr.each {
            if (it in '0'..'9') {
                digits += it
            }
        }

        // give up if there are none
        if (!digits) return 0

        // convert to number
        try {
            def year = NumberFormat.getIntegerInstance().parse(digits)
            if (year < 1500) {
                // unlikely year value
                return 0
            } else {
                return year
            }
        } catch (NumberFormatException e) {
            println "can't parse ${digits} from ${yearStr}"
            return 0
        }
    }
}
